/*
 * Author:   W.SH
 */
package com.wgg.crawler.core;

import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.client.CookieStore;
import org.apache.http.config.SocketConfig;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;

import com.wgg.crawler.model.CrawlerDatum;
import com.wgg.crawler.model.CrawlerDatum.Site;
import com.wgg.util.StringUtils;

/**
 *  HttpClient 封装
 * 
 * @author W.SH
 */
public  class HttpClientGenerator {

    
    private static PoolingHttpClientConnectionManager connManager;
    
    public static final int TTIME_OUT = 5000;
    
    /**
     * 初始化连接池
     */
    static {
        connManager = new PoolingHttpClientConnectionManager();
        connManager.setDefaultMaxPerRoute(100);
    }
    
    public HttpClientGenerator setMaxTotal(int maxTotal){
        connManager.setMaxTotal(maxTotal);
        return this;
    }
    
    public CloseableHttpClient generateClient(CrawlerDatum.Site site) {
        HttpClientBuilder httpClientBuilder = HttpClients.custom().setConnectionManager(connManager);
        
        if (null == site || StringUtils.isBlank(site.getUrl())) {
            return httpClientBuilder.build();
        }
        
        if (!StringUtils.isBlank(site.getUserAgent())) {
            httpClientBuilder.setUserAgent(site.getUserAgent());
        } else {
            httpClientBuilder.setUserAgent("");
        }
        //socketSoTimeout 服务端响应需要等待的时间超时设置
        //TcpNoDelay 开启后容易引起新能为题，导致Nagle算法失效(相当于nio中不使用buffer了,变成了bio中小数据传输)
        SocketConfig config = SocketConfig.custom().setSoKeepAlive(false).setTcpNoDelay(false).setSoTimeout(TTIME_OUT).build();
        httpClientBuilder.setDefaultSocketConfig(config);
        
        generateCookie(httpClientBuilder, site);
        return httpClientBuilder.build();
    }
    
    private void generateCookie(HttpClientBuilder httpClientBuilder, Site site) {
        if (null == site || null == site.getCookies() || site.getCookies().isEmpty()) {
            return;
        }
        Map<String, String> cookies = site.getCookies();
        CookieStore cookieStore = new BasicCookieStore();
        for (Entry<String, String> entry : cookies.entrySet()) {
            BasicClientCookie basicClientCookie = new BasicClientCookie(entry.getKey(), entry.getValue());
            basicClientCookie.setDomain(site.getUrl());
            cookieStore.addCookie(basicClientCookie);
        }
        httpClientBuilder.setDefaultCookieStore(cookieStore);
    }
    
    
    /** 
     * 抓取url请求
     *//*  
    public static FetchedPage doCrawler(String url, Map<String, String> heads) {  
        FetchedPage fechedPage = null;
        try {  
            HttpGet getMethod = new HttpGet(url);  
            if (null != heads) {
                Iterator<Entry<String, String>> entrys = heads.entrySet().iterator();
                while (entrys.hasNext()) {
                    Entry<String, String> entry = entrys.next();
                    getMethod.addHeader(entry.getKey(), entry.getValue());
                }
            }
            HttpResponse response = httpClient.execute(getMethod);  
            int statusCode = response.getStatusLine().getStatusCode();  
            System.out.println("执行状态码 : " + statusCode);  
            HttpEntity entity = response.getEntity();  
            if (entity != null) {  
                fechedPage = new FetchedPage();
                String result = EntityUtils.toString(entity, "UTF-8");  
                fechedPage.setContent(result);
                fechedPage.setStatus(statusCode);
                //获得报文头，得到报文类型
                Header[] headers = response.getHeaders("Content-Type");
                String ContentType = headers[0].getValue();
                int start = ContentType.lastIndexOf("/") + 1;
                int end = ContentType.lastIndexOf(";");
                String type = ContentType.substring(start,end);
                System.out.println("return contentType:" + type);
                if (type.equals("html")) {
                    fechedPage.setType(0);
                } else if (type.equals("json")){
                    fechedPage.setType(1);
                } else if (type.equals("xml")){
                    fechedPage.setType(2);
                }
                fechedPage.setUrl(url);
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        return fechedPage;  
    } 
    
    *//** 
     * 发送 GET 请求（HTTP），不带输入数据 
     *//*  
    public static String doGet(String url) {  
        return doGet(url, new HashMap<String, Object>());  
    }  

    *//** 
     * 发送 GET 请求（HTTP），K-V形式 
     *//*  
    public static String doGet(String url, Map<String, Object> params) {  
        String apiUrl = url;  
        StringBuffer param = new StringBuffer();  
        int i = 0;  
        for (String key : params.keySet()) {  
            if (i == 0)  
                param.append("?");  
            else  
                param.append("&");  
            param.append(key).append("=").append(params.get(key));  
            i++;  
        }  
        apiUrl += param;  
        String result = null;  
        try {  
            HttpGet getMethod = new HttpGet(apiUrl);  
            HttpResponse response = httpClient.execute(getMethod);  
            int statusCode = response.getStatusLine().getStatusCode();  
            System.out.println("执行状态码 : " + statusCode);  
            HttpEntity entity = response.getEntity();  
            if (entity != null) {  
                result = EntityUtils.toString(entity, "UTF-8");  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
    
    *//** 
     * 发送 POST 请求（HTTP），不带输入数据 
     * @param apiUrl 
     * @return 
     *//*  
    public static String doPost(String apiUrl) {  
        return doPostJson(apiUrl, new HashMap<String, Object>());  
    }  
  
    *//** 
     * 发送 POST 请求（HTTP），K-V形式 
     * @param apiUrl API接口URL 
     * @param params 参数map 
     * @return 
     *//*  
    public static String doPost(String apiUrl, Map<String, Object> params) {  
        String httpStr = null;  
        HttpPost httpPost = new HttpPost(apiUrl);  
        CloseableHttpResponse response = null;  
  
        try {  
            List<NameValuePair> pairList = new ArrayList<NameValuePair>(params.size());  
            for (Map.Entry<String, Object> entry : params.entrySet()) {  
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry  
                        .getValue().toString());  
                pairList.add(pair);  
            }  
            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));  
            response = httpClient.execute(httpPost);  
            System.out.println(response.toString());  
            HttpEntity entity = response.getEntity();  
            httpStr = EntityUtils.toString(entity, "UTF-8");  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            if (response != null) {  
                try {  
                    EntityUtils.consume(response.getEntity());  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
        return httpStr;  
    }  
  
    *//** 
     * 发送 POST 请求（HTTP），JSON形式 
     * @param json json对象 
     *//*  
    public static String doPostJson(String apiUrl, Object json) {  
        String httpStr = null;  
        HttpPost httpPost = new HttpPost(apiUrl);  
        CloseableHttpResponse response = null;  
  
        try {  
            StringEntity stringEntity = new StringEntity(json.toString(),"UTF-8");//解决中文乱码问题  
            stringEntity.setContentEncoding("UTF-8");  
            stringEntity.setContentType("application/json");  
            httpPost.setEntity(stringEntity);  
            response = httpClient.execute(httpPost);  
            HttpEntity entity = response.getEntity();  
            System.out.println(response.getStatusLine().getStatusCode());  
            httpStr = EntityUtils.toString(entity, "UTF-8");  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            if (response != null) {  
                try {  
                    EntityUtils.consume(response.getEntity());  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
        return httpStr;  
    }  
    
    *//** 
     * 发送 POST 请求（HTTP），xml形式 
     *//*  
    public static String doPostXml(String apiUrl, String xml) {  
        String httpStr = null;  
        HttpPost httpPost = new HttpPost(apiUrl);  
        CloseableHttpResponse response = null;  
        try {  
            StringEntity stringEntity = new StringEntity(xml,"UTF-8");//解决中文乱码问题  
            stringEntity.setContentEncoding("UTF-8");  
            stringEntity.setContentType("text/xml");  
            httpPost.setEntity(stringEntity);  
            response = httpClient.execute(httpPost);  
            HttpEntity entity = response.getEntity();  
            httpStr = EntityUtils.toString(entity, "UTF-8");  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            if (response != null) {  
                try {  
                    EntityUtils.consume(response.getEntity());  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
        return httpStr;  
    }  
    
    
    *//** 
     * 发送 SSL POST 请求（HTTPS），K-V形式 
     *//*  
    public static String doPostSSL(String apiUrl, Map<String, Object> params) {  
        HttpPost httpPost = new HttpPost(apiUrl);  
        CloseableHttpResponse response = null;  
        String httpStr = null;  
  
        try {  
            List<NameValuePair> pairList = new ArrayList<NameValuePair>(params.size());  
            for (Map.Entry<String, Object> entry : params.entrySet()) {  
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry  
                        .getValue().toString());  
                pairList.add(pair);  
            }  
            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8")));  
            response = httpClient.execute(httpPost);  
            int statusCode = response.getStatusLine().getStatusCode();  
            if (statusCode != HttpStatus.SC_OK) {  
                return null;  
            }  
            HttpEntity entity = response.getEntity();  
            if (entity == null) {  
                return null;  
            }  
            httpStr = EntityUtils.toString(entity, "utf-8");  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (response != null) {  
                try {  
                    EntityUtils.consume(response.getEntity());  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
        return httpStr;  
    }  
    
    
    *//** 
     * 发送 SSL POST 请求（HTTPS），JSON形式 
     * @param json json对象 
     *//*  
    public static String doPostJsonSSL(String apiUrl, Object json) {  
        HttpPost httpPost = new HttpPost(apiUrl);  
        CloseableHttpResponse response = null;  
        String httpStr = null;  
  
        try {  
            StringEntity stringEntity = new StringEntity(json.toString(),"UTF-8");//解决中文乱码问题  
            stringEntity.setContentEncoding("UTF-8");  
            stringEntity.setContentType("application/json");  
            httpPost.setEntity(stringEntity);  
            response = httpClient.execute(httpPost);  
            int statusCode = response.getStatusLine().getStatusCode();  
            if (statusCode != HttpStatus.SC_OK) {  
                return null;  
            }  
            HttpEntity entity = response.getEntity();  
            if (entity == null) {  
                return null;  
            }  
            httpStr = EntityUtils.toString(entity, "utf-8");  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (response != null) {  
                try {  
                    EntityUtils.consume(response.getEntity());  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
        return httpStr;  
    }  
    
    *//** 
     * 发送 SSL POST 请求（HTTPS），xml形式 
     *//*  
    public static String doPostXmlSSL(String apiUrl, String xml) {  
        HttpPost httpPost = new HttpPost(apiUrl);  
        CloseableHttpResponse response = null;  
        String httpStr = null;  
  
        try {  
            StringEntity stringEntity = new StringEntity(xml,"UTF-8");//解决中文乱码问题  
            stringEntity.setContentEncoding("UTF-8");  
            stringEntity.setContentType("text/xml");  
            httpPost.setEntity(stringEntity);  
            response = httpClient.execute(httpPost);  
            int statusCode = response.getStatusLine().getStatusCode();  
            if (statusCode != HttpStatus.SC_OK) {  
                return null;  
            }  
            HttpEntity entity = response.getEntity();  
            if (entity == null) {  
                return null;  
            }  
            httpStr = EntityUtils.toString(entity, "utf-8");  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (response != null) {  
                try {  
                    EntityUtils.consume(response.getEntity());  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
        return httpStr;  
    }  */
  
    
    /** 
     * 创建SSL安全连接 
     * 
     * @return 
     */  
/*    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {  
        SSLConnectionSocketFactory sslsf = null;  
        try {  
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {  
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
                    return true;  
                }  
            }).build();  
            sslsf = new SSLConnectionSocketFactory(sslContext);
        } catch (GeneralSecurityException e) {  
            e.printStackTrace();  
        }  
        return sslsf;  
    }  */
}
